<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>Expand Nodes with Force Layout</title>
  </head>

  <body>
    <div id="mountNode"></div>
    <script src="../build/g6.js"></script>
    <script src="../build/force.js"></script>
    <script src="./assets/d3-4.13.0.min.js"></script>
    <script>
      const getNodeById = {
        success: true,
        data: {
          nodes: [
            {
              id: '20',
              nodeType: 'Person',
              label: 'name1',
              properties: {
                age: '37',
                annualIncome: '0',
                career: '',
                credit: '',
                education: '',
                email: '',
                gender: 'M',
                highestEducation: '',
                isBusiness: '',
                isOnBlacklist: '',
                name: 'name1',
                permanentResidenceAddress: '',
                residentialAddress: '',
                sbh: '',
                telephone: '',
                workUnit: '',
              },
            },
            {
              id: '1',
              nodeType: 'Person',
              label: 'name2',
              properties: {
                age: '31',
                annualIncome: '0',
                career: '',
                credit: '',
                education: '',
                email: '',
                gender: 'FM',
                highestEducation: '',
                isBusiness: '',
                isOnBlacklist: '',
                name: 'name2',
                permanentResidenceAddress: '',
                residentialAddress: '',
                sbh: '',
                telephone: '',
                workUnit: '',
              },
            },
          ],
          edges: [
            {
              source: '20',
              target: '1',
            },
          ],
          queryResult: '',
          graphView: true,
        },
        errorCode: null,
        msg: null,
      };

      // 根据节点扩展
      const getNodesByNodeId = {
        success: true,
        data: {
          nodes: [
            {
              id: '20',
              nodeType: 'Person',
              label: '祁同伟',
              properties: {
                age: '37',
                annualIncome: '0',
                career: '',
                credit: '',
                education: '',
                email: '',
                gender: 'M',
                highestEducation: '',
                isBusiness: '',
                isOnBlacklist: '',
                name: '祁同伟',
                permanentResidenceAddress: '',
                residentialAddress: '',
                sbh: '',
                telephone: '',
                workUnit: '',
              },
            },
            {
              id: '22',
              nodeType: 'Person',
              label: '高晓秦',
              properties: {
                age: '23',
                annualIncome: '0',
                career: '',
                credit: '',
                education: '',
                email: '',
                gender: 'F',
                highestEducation: '',
                isBusiness: '',
                isOnBlacklist: '',
                name: '高晓秦',
                permanentResidenceAddress: '',
                residentialAddress: '',
                sbh: '',
                telephone: '',
                workUnit: '',
              },
            },
            {
              id: '10',
              nodeType: 'Person',
              label: '高育良',
              properties: {
                age: '57',
                annualIncome: '0',
                career: '',
                credit: '',
                education: '',
                email: '',
                gender: 'M',
                highestEducation: '',
                isBusiness: '',
                isOnBlacklist: '',
                name: '高育良',
                permanentResidenceAddress: '',
                residentialAddress: '',
                sbh: '',
                telephone: '',
                workUnit: '',
              },
            },
            {
              id: '12',
              nodeType: 'Person',
              label: '高晓凤',
              properties: {
                age: '22',
                annualIncome: '0',
                career: '',
                credit: '',
                education: '',
                email: '',
                gender: 'F',
                highestEducation: '',
                isBusiness: '',
                isOnBlacklist: '',
                name: '高晓凤',
                permanentResidenceAddress: '',
                residentialAddress: '',
                sbh: '',
                telephone: '',
                workUnit: '',
              },
            },
            {
              id: '21',
              nodeType: 'Person',
              label: '梁璐',
              properties: {
                age: '40',
                annualIncome: '0',
                career: '',
                credit: '',
                education: '',
                email: '',
                gender: 'F',
                highestEducation: '',
                isBusiness: '',
                isOnBlacklist: '',
                name: '梁璐',
                permanentResidenceAddress: '',
                residentialAddress: '',
                sbh: '',
                telephone: '',
                workUnit: '',
              },
            },
            {
              id: '11',
              nodeType: 'Person',
              label: '吴淑芬',
              properties: {
                age: '50',
                annualIncome: '0',
                career: '',
                credit: '',
                education: '',
                email: '',
                gender: 'F',
                highestEducation: '',
                isBusiness: '',
                isOnBlacklist: '',
                name: '吴淑芬',
                permanentResidenceAddress: '',
                residentialAddress: '',
                sbh: '',
                telephone: '',
                workUnit: '',
              },
            },
            {
              id: '100',
              nodeType: 'Enterprise',
              label: '小米',
              properties: {
                IsChineseFunded: '',
                businessScope: '',
                credit: '',
                employeesNumber: '0',
                enterpriseNature: '',
                establishmentTime: '',
                holdingType: '',
                importExportRightMark: '',
                industryType: '',
                isAdvantageEnterprise: '',
                isLeadingEnterprise: '',
                isOnBlacklist: '',
                isOvercapacity: '',
                isRegionalKeyEnterprise: '',
                isSangaoEnterprise: '',
                name: '小米',
                registeredCapital: '0',
                registrationAddress: '',
                sbh: '',
                size: '',
                stockCode: '',
                telephone: '',
              },
            },
            {
              id: '102',
              nodeType: 'Enterprise',
              label: '茅台',
              properties: {
                IsChineseFunded: '',
                businessScope: '',
                credit: '',
                employeesNumber: '0',
                enterpriseNature: '',
                establishmentTime: '',
                holdingType: '',
                importExportRightMark: '',
                industryType: '',
                isAdvantageEnterprise: '',
                isLeadingEnterprise: '',
                isOnBlacklist: '',
                isOvercapacity: '',
                isRegionalKeyEnterprise: '',
                isSangaoEnterprise: '',
                name: '茅台',
                registeredCapital: '0',
                registrationAddress: '',
                sbh: '',
                size: '',
                stockCode: '',
                telephone: '',
              },
            },
          ],
          edges: [
            {
              target: '100',
              source: '20',
            },
            {
              target: '102',
              source: '20',
            },
            {
              target: '10',
              source: '20',
            },
            {
              target: '11',
              source: '20',
            },
            {
              target: '21',
              source: '20',
            },
            {
              target: '21',
              source: '20',
            },
            {
              target: '22',
              source: '20',
            },
            {
              target: '11',
              source: '10',
            },
            {
              target: '12',
              source: '10',
            },
            {
              target: '22',
              source: '21',
            },
            {
              target: '22',
              source: '12',
            },
          ],
          queryResult: '',
          graphView: true,
        },
        errorCode: null,
        msg: null,
      };

      // 根据节点扩展
      const getNodesByNodeId2 = {
        success: true,
        data: {
          nodes: [
            {
              id: '22',
              nodeType: 'Person',
              label: '高晓秦',
              properties: {
                age: '23',
                annualIncome: '0',
                career: '',
                credit: '',
                education: '',
                email: '',
                gender: 'F',
                highestEducation: '',
                isBusiness: '',
                isOnBlacklist: '',
                name: '高晓秦',
                permanentResidenceAddress: '',
                residentialAddress: '',
                sbh: '',
                telephone: '',
                workUnit: '',
              },
            },
            {
              id: '1000',
              nodeType: 'Person',
              label: '晓秦1',
              properties: {
                age: '57',
                annualIncome: '0',
                career: '',
                credit: '',
                education: '',
                email: '',
                gender: 'M',
                highestEducation: '',
                isBusiness: '',
                isOnBlacklist: '',
                name: '晓秦1',
                permanentResidenceAddress: '',
                residentialAddress: '',
                sbh: '',
                telephone: '',
                workUnit: '',
              },
            },
            {
              id: '1001',
              nodeType: 'Person',
              label: '晓秦2',
              properties: {
                age: '22',
                annualIncome: '0',
                career: '',
                credit: '',
                education: '',
                email: '',
                gender: 'F',
                highestEducation: '',
                isBusiness: '',
                isOnBlacklist: '',
                name: '晓秦2',
                permanentResidenceAddress: '',
                residentialAddress: '',
                sbh: '',
                telephone: '',
                workUnit: '',
              },
            },
            {
              id: '1002',
              nodeType: 'Person',
              label: '晓秦3',
              properties: {
                age: '40',
                annualIncome: '0',
                career: '',
                credit: '',
                education: '',
                email: '',
                gender: 'F',
                highestEducation: '',
                isBusiness: '',
                isOnBlacklist: '',
                name: '晓秦3',
                permanentResidenceAddress: '',
                residentialAddress: '',
                sbh: '',
                telephone: '',
                workUnit: '',
              },
            },
            {
              id: '1003',
              nodeType: 'Person',
              label: '晓秦4',
              properties: {
                age: '40',
                annualIncome: '0',
                career: '',
                credit: '',
                education: '',
                email: '',
                gender: 'F',
                highestEducation: '',
                isBusiness: '',
                isOnBlacklist: '',
                name: '晓秦4',
                permanentResidenceAddress: '',
                residentialAddress: '',
                sbh: '',
                telephone: '',
                workUnit: '',
              },
            },
            {
              id: '1004',
              nodeType: 'Person',
              label: '晓秦5',
              properties: {
                age: '40',
                annualIncome: '0',
                career: '',
                credit: '',
                education: '',
                email: '',
                gender: 'F',
                highestEducation: '',
                isBusiness: '',
                isOnBlacklist: '',
                name: '晓秦5',
                permanentResidenceAddress: '',
                residentialAddress: '',
                sbh: '',
                telephone: '',
                workUnit: '',
              },
            },
          ],
          edges: [
            {
              target: '22',
              source: '1000',
            },
            {
              target: '22',
              source: '1001',
            },
            {
              target: '22',
              source: '1002',
            },
            {
              target: '1001',
              source: '1002',
            },
            {
              target: '1000',
              source: '1',
            },
            {
              target: '20',
              source: '1002',
            },
            {
              target: '22',
              source: '1003',
            },
            {
              target: '22',
              source: '1004',
            },
          ],
          queryResult: '',
          graphView: true,
        },
        errorCode: null,
        msg: null,
      };

      let clickedNodeId = -1;
      let clickedNodePos = {
        x: 500,
        y: 300,
      };

      // 封装点击添加边的交互
      G6.registerBehavior('click-add-node', {
        getEvents() {
          return {
            'node:click': 'onClick',
          };
        },
        onClick(ev) {
          const itemModel = ev.item.getModel();
          clickedNodeId = itemModel.id;
          clickedNodePos.x = itemModel.x;
          clickedNodePos.y = itemModel.y;
          const graph = this.graph;
          const nodes = graph.getNodes();
          const edges = graph.getEdges();
          let newData = getNodeById.data;
          if (itemModel.id == 20) newData = getNodesByNodeId.data;
          else if (itemModel.id == 22) newData = getNodesByNodeId2.data;
          let newNodeModels = newData.nodes;
          let newEdgeModels = newData.edges;
          let allNodeModels = [],
            allEdgeModels = [];

          // fix the existing nodes by set the fx and fy to the current value
          // to cancel the fix the node, set fx = null fy = null
          nodes.forEach((n, i) => {
            const model = n.getModel();
            model.fixed = true;
            model.fx = model.x;
            model.fy = model.y;
            allNodeModels.push(model);
          });

          newNodeModels.forEach((nodeModel, i) => {
            // if it does not exist in nodes
            let exist = false;
            nodes.forEach((n, i) => {
              if (n.getModel().id == nodeModel.id) {
                exist = true;
                return;
              }
            });
            // then add it into graph
            if (!exist) {
              // set the initial positions of the new nodes at the clicked node
              nodeModel.x = itemModel.x;
              nodeModel.y = itemModel.y;
              const node = graph.addItem('node', nodeModel);
              allNodeModels.push(nodeModel);
              nodes.push(node);
            }
          });

          newEdgeModels.forEach((em, i) => {
            // if it does not exist in nodes
            let exist = false;
            edges.forEach((e, i) => {
              const eModel = e.getModel();
              if (eModel.source == em.source && eModel.target == em.target) {
                exist = true;
                return;
              }
            });
            if (!exist) {
              const edge = graph.addItem('edge', em);
              edges.push(edge);
            }
          });
          edges.forEach((e, i) => {
            allEdgeModels.push(e.getModel());
          });

          graph.changeData({
            nodes: allNodeModels,
            edges: allEdgeModels,
          });
        },
      });

      let data = getNodeById.data;

      const graph = new G6.Graph({
        container: 'mountNode',
        width: 1000,
        height: 600,
        layout: {
          type: 'force',
          center: [500, 300],
          // 向心力作用点
          nodeStrength: -30,
          // 节点作用力
          preventOverlap: true,
          // 是否防止节点相互覆盖
          nodeSize: 40,
          // 节点大小 / 直径
          edgeStrength: 0.1,
          // 边的作用力, 默认为根据节点的入度出度自适应
          linkDistance: 100,
          // 默认边长度
        },
        modes: {
          default: ['drag-node', 'click-select', 'click-add-node'],
        },
        defaultNode: {
          size: [40, 40],
          color: 'steelblue',
        },
        defaultEdge: {
          size: 1,
          color: '#e2e2e2',
        },
      });

      graph.data(data);

      graph.render();
      graph.on('node:dragend', ev => {
        const itemModel = ev.item.getModel();
        itemModel.fixed = true;
        itemModel.fx = ev.x;
        itemModel.fy = ev.y;
      });
    </script>
  </body>
</html>
